package com.zyl.blog.common.utils.Extreme;

import org.springframework.cglib.beans.BeanCopier;
import org.springframework.cglib.core.Converter;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 高性能Bean属性拷贝工具类
 *
 * <p>基于CGLIB BeanCopier实现，具有以下特性：
 * <ul>
 *   <li>自动缓存BeanCopier实例，避免重复创建的开销</li>
 *   <li>支持单个对象和集合的深度拷贝</li>
 *   <li>空值安全处理（source为null时返回null）</li>
 * </ul>
 *
 * @version v1.0
 * @ProjectName: Personal_Blog
 * @Package: com.zyl.common.utils.Extreme
 * @ClassName: BeanConvertUtil
 * @Author FinalFantasy
 * @Date 2025/2/14-16:49
 */
public final class BeanConvertUtil {

    // 使用缓存提升性能
    private static final Map<String, BeanCopier> BEAN_COPIER_CACHE = new ConcurrentHashMap<>();

    // 自定义字段映射注解
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface FieldMapping {
        String value() default "";

        Class<? extends Converter> converter() default Converter.class;
    }

    public static <T> T copy(Object source, Class<T> targetClass) {
        if (source == null) return null;

        try {
            T target = targetClass.getDeclaredConstructor().newInstance();
            BeanCopier copier = getBeanCopier(source.getClass(), targetClass);
            copier.copy(source, target, new CustomConverter(source.getClass(), targetClass));
            return target;
        } catch (ReflectiveOperationException ex) {
            throw new RuntimeException("对象拷贝失败", ex);
        }
    }

    private static BeanCopier getBeanCopier(Class<?> sourceClass, Class<?> targetClass) {
        String key = sourceClass.getName() + "_" + targetClass.getName();
        return BEAN_COPIER_CACHE.computeIfAbsent(key, k ->
                BeanCopier.create(sourceClass, targetClass, true));
    }

    private record CustomConverter(Class<?> sourceClass, Class<?> targetClass) implements Converter {
        @Override
        public Object convert(Object value, Class targetType, Object context) {
            try {
                // 处理字段映射
                String setterMethod = (String) context;
                Field targetField = getTargetField(setterMethod);
                FieldMapping mapping = targetField.getAnnotation(FieldMapping.class);

                // 获取实际要拷贝的源字段值
                if (mapping != null && !mapping.value().isEmpty()) {
                    Field sourceField = sourceClass.getDeclaredField(mapping.value());
                    sourceField.setAccessible(true);
                    value = sourceField.get(value);
                }

                // 类型转换处理
                if (value == null) return null;
                if (targetType.isAssignableFrom(value.getClass())) return value;

                // 自定义转换器
                if (mapping != null && mapping.converter() != Converter.class) {
                    Converter converter = mapping.converter().newInstance();
                    return converter.convert(value, targetType, context);
                }

                // 添加其他默认类型转换逻辑（示例：Date转String）
                if (value instanceof Date && targetType == String.class) {
                    return new SimpleDateFormat("yyyy-MM-dd").format((Date) value);
                }

                // 递归处理嵌套对象
                return copy(value, targetType);
            } catch (Exception e) {
                throw new RuntimeException("字段转换失败", e);
            }
        }

        private Field getTargetField(String setterMethod) throws NoSuchFieldException {
            String fieldName = setterMethod.replace("set", "");
            fieldName = fieldName.substring(0, 1).toLowerCase() + fieldName.substring(1);
            return targetClass.getDeclaredField(fieldName);
        }
    }
}